import { loadConfig } from './config.ts'
import * as mqtt from './mqtt.ts'
import * as procReport from './proc/report.ts'
import * as procPersisHistory from './proc/persist/history.ts'
import * as procPersisStatus from './proc/persist/status.ts'
import * as procPost from './proc/post.ts'
import * as ota from "./proc/ota.ts"
import * as print from "./proc/print.ts"
import { DataSource } from 'typeorm'
import Redis from 'ioredis'



// 捕获未处理的Promise拒绝
process.on('unhandledRejection', async (reason, promise) => {
    // 加载配置
    let config = await loadConfig();
    // console.error('未处理的Promise拒绝:', reason);
    if (reason == 'Error: connect ECONNREFUSED 115.159.127.169:3306') {
        console.log('重连数据库')
        // 重连数据库
        tryReconnectDatabase(config);
    }

    // 这里可以选择终止进程或者尝试重试数据库连接
    // 可以选择自动重启应用，或者简单地记录错误
    // 你可以在这里添加重连数据库的逻辑，或进行其他清理操作
});

// 捕获未捕获的异常
process.on('uncaughtException', (err) => {
    console.error('未捕获的异常:', err);
    // 这里可以做错误记录、应用重启、数据库重连等处理
    // 例如：如果数据库连接丢失，尝试重连数据库
    // 或者你可以选择退出应用，等待外部进程重启
    // 例如：process.exit(1);  // 强制退出
});

// 尝试初始化数据库连接
async function initializeDatabase(config: any): Promise<DataSource | null> {
    const AppDataSource = new DataSource(config.default.typeorm.dataSource.default);
    try {
        await AppDataSource.initialize();
        console.log("数据库连接成功！");
        return AppDataSource;
    } catch (error) {
        console.error("数据库连接失败:", error);
        handleDbConnectionError(error);  // 调用错误处理函数
        return null;  // 返回 null 表示数据库连接失败
    }
}

// 处理数据库连接错误
function handleDbConnectionError(err: any) {
    if (err.code === 'ECONNRESET' || err.code === 'ECONNREFUSED') {
        // console.error("数据库连接错误: 连接被重置或拒绝", err);
        // 可以在这里执行自定义的错误处理，例如日志记录、重试机制等
    } else {
        // console.error("数据库连接未知错误:", err);
        // 其他错误可以选择抛出或者记录日志
    }
}


// 尝试重新连接数据库
async function tryReconnectDatabase(config: any): Promise<DataSource | null> {
    let dbConnection = null;
    while (true) {
        dbConnection = await initializeDatabase(config);
        if (dbConnection) {
            break;
        }
        console.log("数据库连接失败，等待 2 秒后重试...");
        await new Promise(resolve => setTimeout(resolve, 2000));  // 等待 2 秒后重试
    }
    return dbConnection;
}

async function main() {
    let config = await loadConfig();
    console.log('config', config);

    // 启动 Redis 客户端
    const redisClient = new Redis({
        host: config.default.redis.host,
        port: config.default.redis.port,
        retryStrategy: (times) => Math.min(times * 50, 2000)
    });

    redisClient.on('connect', () => {
        console.log('Redis connected');
    });

    redisClient.on('error', (err) => {
        console.error('Redis Error:', err);
    });

    // 初始化 MQTT 客户端
    await mqtt.init(config.default.mqtt.suzhou.host);
    const clientShanghai = await mqtt.init(config.default.mqtt.shanghai.host);

    let AppDataSource = null;
    let dbConnected = false;

    // 尝试初始化数据库连接
    try {
        AppDataSource = await initializeDatabase(config);
        dbConnected = AppDataSource !== null;
    } catch (err) {
        console.log('数据库连接初始化失败:', err);
    }

    print.setup(); // 测试模块
    procReport.setup();  // 数据报告模块

    if (dbConnected) {
        console.log("数据库连接成功！")
        // 如果有数据库连接，继续执行相关模块
        procPersisHistory.setup(AppDataSource);  // 历史数据持久化模块
        procPersisStatus.setup(AppDataSource);  // 实时数据持久化模块
        ota.setup(AppDataSource);  // OTA 更新模块
        procPost.setup(AppDataSource, clientShanghai, redisClient);
    } else {
        console.log('数据库连接失败，应用继续运行，但没有数据库支持...');
        // 数据库连接失败时，继续运行不依赖数据库的模块
        procPost.setup(null, clientShanghai, redisClient);  // 即使没有数据库连接，也继续上报数据
        ota.setup(null);  // OTA 更新模块
        procPersisHistory.setup(null);  // 历史数据持久化模块
        procPersisStatus.setup(null);  // 实时数据持久化模块
    }

    console.log("应用已经启动 ...");

    // 定期检查数据库连接状态并尝试重新连接
    setInterval(async () => {
        if (!dbConnected) {
            console.log("尝试重新连接数据库...");
            AppDataSource = await tryReconnectDatabase(config);
            dbConnected = AppDataSource !== null;
            if (dbConnected) {
                console.log("数据库连接恢复成功！");
                procPersisHistory.setup(AppDataSource);  // 恢复历史数据持久化模块
                procPersisStatus.setup(AppDataSource);  // 恢复实时数据持久化模块
                ota.setup(AppDataSource);  // 恢复 OTA 更新模块
                procPost.setup(AppDataSource, clientShanghai, redisClient);  // 恢复数据上报模块
            }
        }
    }, 30000);  // 每 30 秒检查一次数据库连接状态
}

// 运行主函数
main().catch(error => {
    console.error('应用启动过程中出错:', error);
});
